package com.liuzy.family.captcha;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import com.liuzy.family.util.DateKit;
import com.liuzy.family.util.HTTP;
import com.liuzy.family.util.StrKit;

/**
 * 阿里大鱼短信接口
 * http://www.alidayu.com/admin/user/account
 * 
 * @author liuzy
 * @since 2016年2月24日
 */
public class Sender {
	public static final String key = "23315385";
	public static final String secret = "4bc86832cbb24acc525105ef912a52f3";

	public static final String SIGN_METHOD_MD5 = "md5";
	public static final String SIGN_METHOD_HMAC = "hmac";
	public static final String CHARSET_UTF8 = "UTF-8";

	public static void main(String[] args) throws IOException {
		String url = "http://gw.api.taobao.com/router/rest";
		Map<String, String> bodyMap = new HashMap<>();
		bodyMap.put("method", "alibaba.aliqin.fc.sms.num.send");//API接口名称。
		bodyMap.put("app_key", key);//TOP分配给应用的AppKey。
		bodyMap.put("session", "");//API的标签上注明：“需要授权”，则此参数必传；“不需要授权”，则此参数不需要传；
		bodyMap.put("timestamp", DateKit.format(new Date()));//时间戳，格式为yyyy-MM-dd HH:mm:ss，时区为GMT+8
		bodyMap.put("format", "json");//响应格式，可选值：xml，json。
		bodyMap.put("v", "2.0");//API协议版本
		bodyMap.put("partner_id", "");//合作伙伴身份标识。
		bodyMap.put("target_app_key", "");//被调用的目标AppKey
		bodyMap.put("simplify", "false");//是否采用精简JSON返回格式
		bodyMap.put("sign_method", "md5");//签名的摘要算法，可选值为：hmac，md5。

		bodyMap.put("sms_type", "normal");//短信类型，传入值请填写normal
		bodyMap.put("sms_free_sign_name", "注册验证");//短信签名
		bodyMap.put("sms_param", "{\"code\":\""+StrKit.randomNum(6)+"\",\"product\":\"VA伐木累\"}");//短信模板变量
		bodyMap.put("rec_num", "13162165337");//短信接收号码
		bodyMap.put("sms_template_code", "SMS_4994298");//短信模板ID

		bodyMap.put("sign", signTopRequest(bodyMap, secret, "md5"));//签名
		HTTP http = new HTTP();
		String r = http.doPOST(url, null, null, bodyMap);
		System.out.println(r);
	}

	public static String signTopRequest(Map<String, String> params, String secret, String signMethod) throws IOException {
	    // 第一步：检查参数是否已经排序
	    String[] keys = params.keySet().toArray(new String[0]);
	    Arrays.sort(keys);
	 
	    // 第二步：把所有参数名和参数值串在一起
	    StringBuilder query = new StringBuilder();
	    if (SIGN_METHOD_MD5.equals(signMethod)) {
	        query.append(secret);
	    }
	    for (String key : keys) {
	        String value = params.get(key);
	        if (value != null) {
	            query.append(key).append(value);
	        }
	    }
	 
	    // 第三步：使用MD5/HMAC加密
	    byte[] bytes;
	    if (SIGN_METHOD_HMAC.equals(signMethod)) {
	        bytes = encryptHMAC(query.toString(), secret);
	    } else {
	        query.append(secret);
	        bytes = encryptMD5(query.toString());
	    }
	 
	    // 第四步：把二进制转化为大写的十六进制
	    return byte2hex(bytes);
	}
	 
	public static byte[] encryptHMAC(String data, String secret) throws IOException {
	    byte[] bytes = null;
	    try {
	        SecretKey secretKey = new SecretKeySpec(secret.getBytes(CHARSET_UTF8), "HmacMD5");
	        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
	        mac.init(secretKey);
	        bytes = mac.doFinal(data.getBytes(CHARSET_UTF8));
	    } catch (GeneralSecurityException gse) {
	        throw new IOException(gse.toString());
	    }
	    return bytes;
	}
	 
	public static byte[] encryptMD5(String data) throws IOException {
		try {
			byte[] bytes = data.getBytes(CHARSET_UTF8);
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			mdInst.update(bytes);
			return mdInst.digest();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return null;
		}
	}

	public static String byte2hex(byte[] bytes) {
	    StringBuilder sb = new StringBuilder();
	    for (int i = 0; i < bytes.length; i++) {
	        String hex = Integer.toHexString(bytes[i] & 0xFF);
	        if (hex.length() == 1) {
	            sb.append("0");
	        }
	        sb.append(hex.toUpperCase());
	    }
	    return sb.toString();
	}
}
